package top.cardone.data.action;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.util.action.Action0;
import top.cardone.data.service.CrudService;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author yao hai tao
 * @date 2017/7/18
 */
@Log4j2
public class GenerateTreeAction implements Action0 {
    private static int actionCount = 0;

    @Setter
    private Class<? extends CrudService> serviceBeanType;

    @Setter
    private String orderByPutKey = "order_by_orderBy";

    @Setter
    private String parentCodePutKey = "parentCode";

    @Setter
    private String parentIdPutKey = "parentId";

    @Setter
    private String parentCodeGetKey = "PARENT_CODE";

    @Setter
    private String parentIdGetKey = "PARENT_ID";

    @Setter
    private String codePutKey = "code";

    @Setter
    private String codeGetKey = "CODE";

    @Setter
    private String parentTreeCodePutKey = "parentTreeCode";

    @Setter
    private String parentTreeIdPutKey = "parentTreeId";

    @Setter
    private String parentTreeCodeGetKey = "PARENT_TREE_CODE";

    @Setter
    private String parentTreeIdGetKey = "PARENT_TREE_ID";

    @Setter
    private String parentTreeNamePutKey = "parentTreeName";

    @Setter
    private String parentTreeNameGetKey = "PARENT_TREE_NAME";

    @Setter
    private String nameGetKey = "NAME";

    @Setter
    private String pkPutKey = "id";

    @Setter
    private String pkGetKey = "ID";

    @Setter
    private String dataStateCodePutKey = "dataStateCode";

    public void fixTreeInfo(List<Map<String, Object>> items) {
        Map<String, Object> fixMap = Maps.newHashMap();

        fixMap.put(this.parentIdGetKey, StringUtils.EMPTY);
        fixMap.put(this.parentCodeGetKey, StringUtils.EMPTY);
        fixMap.put(this.parentTreeIdGetKey, StringUtils.EMPTY);
        fixMap.put(this.parentTreeCodeGetKey, StringUtils.EMPTY);
        fixMap.put(this.parentTreeNameGetKey, StringUtils.EMPTY);

        for (Map<String, Object> item : items) {
            String itemId = MapUtils.getString(item, this.pkGetKey, StringUtils.EMPTY);
            String itemCode = MapUtils.getString(item, this.codeGetKey, StringUtils.EMPTY);
            String itemParentId = MapUtils.getString(item, this.parentIdGetKey, StringUtils.EMPTY);
            String itemParentCode = MapUtils.getString(item, this.parentCodeGetKey, StringUtils.EMPTY);

            if (StringUtils.isBlank(itemParentId)) {
                if (StringUtils.isBlank(itemParentCode)) {
                    item.putAll(fixMap);

                    continue;
                }

                itemParentId = MapUtils.getString(items.stream().filter(map -> Objects.equals(map.get(this.codeGetKey), MapUtils.getString(item, this.parentCodeGetKey, StringUtils.EMPTY))).findFirst().orElse(Maps.newHashMap()), this.pkGetKey);

                if (StringUtils.isBlank(itemParentId)) {
                    item.putAll(fixMap);

                    continue;
                }

                item.put(this.parentIdGetKey, itemParentId);
            } else if (StringUtils.isBlank(itemParentCode)) {
                itemParentCode = MapUtils.getString(items.stream().filter(map -> Objects.equals(map.get(this.pkGetKey), MapUtils.getString(item, this.parentIdGetKey, StringUtils.EMPTY))).findFirst().orElse(Maps.newHashMap()), this.codeGetKey, itemParentId);

                item.put(this.parentCodeGetKey, itemParentCode);
            }

            if (Objects.equals(itemParentId, itemId)) {
                item.putAll(fixMap);

                continue;
            }

            if (StringUtils.contains(MapUtils.getString(item, this.parentTreeCodeGetKey, StringUtils.EMPTY), itemCode)) {
                item.putAll(fixMap);

                continue;
            }

            if (StringUtils.contains(MapUtils.getString(item, this.parentTreeIdGetKey, StringUtils.EMPTY), itemId)) {
                item.putAll(fixMap);

                continue;
            }

            Map<String, Object> parent = items.stream().filter(map -> Objects.equals(map.get(this.pkGetKey), MapUtils.getString(item, this.parentIdGetKey, StringUtils.EMPTY))).findFirst().orElse(Maps.newHashMap());

            if (Objects.equals(MapUtils.getString(parent, this.parentIdGetKey, StringUtils.EMPTY), itemId)) {
                item.putAll(fixMap);

                continue;
            }

            if (StringUtils.contains(MapUtils.getString(parent, this.parentTreeCodeGetKey, StringUtils.EMPTY), itemCode)) {
                item.putAll(fixMap);

                continue;
            }

            if (StringUtils.contains(MapUtils.getString(parent, this.parentTreeIdGetKey, StringUtils.EMPTY), itemId)) {
                item.putAll(fixMap);

                continue;
            }
        }
    }

    private void generateTreeInfo(Map<String, Object> parent, List<Map<String, Object>> items, int dept, List<Object> updateList) {
        String parentId = MapUtils.getString(parent, this.parentIdGetKey, StringUtils.EMPTY);
        String parentCode = MapUtils.getString(parent, this.parentCodeGetKey, StringUtils.EMPTY);
        String parentTreeId = MapUtils.getString(parent, this.parentTreeIdGetKey, parentId);
        String parentTreeCode = MapUtils.getString(parent, this.parentTreeCodeGetKey, parentCode);
        String parentTreeName = MapUtils.getString(parent, this.parentTreeNameGetKey, parentTreeCode);

        if (parent != null) {
            String id = MapUtils.getString(parent, this.pkGetKey, StringUtils.EMPTY);

            Map<String, Object> update = Maps.newHashMap();

            update.put(this.pkPutKey, id);
            update.put(this.parentIdPutKey, parentId);
            update.put(this.parentCodePutKey, parentCode);
            update.put(this.parentTreeIdPutKey, StringUtils.defaultString(parentTreeId, parentId));
            update.put(this.parentTreeCodePutKey, StringUtils.defaultString(parentTreeCode, parentCode));
            update.put(this.parentTreeNamePutKey, StringUtils.defaultString(parentTreeName, parentCode));

            updateList.add(update);
        }

        if (CollectionUtils.isEmpty(items) || dept < 1) {
            return;
        }

        parentId = MapUtils.getString(parent, this.pkGetKey, StringUtils.EMPTY);

        parentCode = MapUtils.getString(parent, this.codeGetKey, parentId);

        for (Map<String, Object> item : items) {
            String itemParentId = MapUtils.getString(item, this.parentIdGetKey, StringUtils.EMPTY);

            if (!StringUtils.equals(parentId, itemParentId)) {
                continue;
            }

            if (StringUtils.isNotBlank(parentTreeId)) {
                item.put(this.parentTreeIdGetKey, parentTreeId + "," + parentId);
                item.put(this.parentTreeCodeGetKey, parentTreeCode + "," + parentCode);
                item.put(this.parentTreeNameGetKey, parentTreeName + "," + MapUtils.getString(parent, this.nameGetKey, parentCode));
            } else {
                item.put(this.parentTreeIdGetKey, parentId);
                item.put(this.parentTreeCodeGetKey, parentCode);
                item.put(this.parentTreeNameGetKey, MapUtils.getString(parent, this.nameGetKey, parentCode));
            }

            item.put(this.parentCodeGetKey, parentCode);

            this.generateTreeInfo(item, items, (dept - 1), updateList);

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                log.error(e);
            }
        }
    }

    @Override
    public void action() {
        if (actionCount > 1) {
            return;
        }

        actionCount++;

        if (actionCount > 1) {
            return;
        }

        while (actionCount > 0) {
            try {
                Map<String, Object> findListMap = Maps.newHashMap();

                findListMap.put(this.orderByPutKey, "asc");
                findListMap.put(this.dataStateCodePutKey, "1");

                for (int i = 0; i < 3; i++) {
                    List<Object> updateList = Lists.newArrayList();

                    List<Map<String, Object>> items = ApplicationContextHolder.getBean(serviceBeanType).findList(findListMap);

                    if (actionCount > 1) {
                        break;
                    }

                    this.fixTreeInfo(items);

                    if (actionCount > 1) {
                        break;
                    }

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        log.error(e);
                    }

                    generateTreeInfo(null, items, 6, updateList);

                    if (actionCount > 1) {
                        break;
                    }

                    if (!org.springframework.util.CollectionUtils.isEmpty(updateList)) {
                        ApplicationContextHolder.getBean(serviceBeanType).updateList(updateList);
                    }
                }

                Thread.sleep(3000);
            } catch (InterruptedException e) {
                log.error(e);
            } finally {
                actionCount--;
            }
        }
    }
}
